/*
* Copyright 2009 W. De Bie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.granizo.treetag;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import org.granizo.treetag.util.CollectionUtil;

public class TreeTag extends SimpleTagSupport {
	enum VisitorStatus {BEFORE, AFTER}
	
	private Object tree;
	private String connectMethod;
	private String var;
	private VisitorStatus visitorStatus;
	
	public void doTag() throws JspException, IOException {
		Collection<?> coll = CollectionUtil.toCollection(tree);
		doProcessing(coll, 0);
	}
	
	public void setTree(Object tree) {
		this.tree = tree;
	}
	
	public void setConnectMethod(String connectMethod) {
		this.connectMethod = connectMethod;
	}
	
	public void setVar(String var) {
		this.var = var;
	}
	
	public boolean startElementExecution() {
		return visitorStatus == VisitorStatus.BEFORE;
	}
	
	public boolean endElementExecution() {
		return visitorStatus == VisitorStatus.AFTER;
	}
	
	private void doProcessing(Collection<?> currentElements, int level) 
	throws JspException, IOException{
		boolean hasChildren = false;
		
		for(Object o : currentElements) {
			TreeTraversalStatus traversalStatus = new TreeTraversalStatus();
			traversalStatus.setLevel(level);
			traversalStatus.setElement(o);
			
			Collection<?> currentChildren = null;
			try {
				Method method = o.getClass().getMethod(connectMethod);
				// Method exists
				Object result = method.invoke(o);
				if(result != null) {
					currentChildren = CollectionUtil.toCollection(result);
					hasChildren = true;
				} else {
					hasChildren = false;
				}
			} catch(NoSuchMethodException e) {
				hasChildren = false;
			} catch(InvocationTargetException e) {
				hasChildren = false;
			} catch(IllegalAccessException e) {
				hasChildren = false;
			}
			
			invokeBody(VisitorStatus.BEFORE, traversalStatus);
			if(hasChildren) {
				doProcessing(currentChildren, level + 1);
			}
			invokeBody(VisitorStatus.AFTER, traversalStatus);
		}
	}
	
	private void invokeBody(VisitorStatus visitorStatus, TreeTraversalStatus traversalStatus) 
	throws JspException, IOException {
		this.visitorStatus = visitorStatus;
		getJspContext().setAttribute(var, traversalStatus);
		getJspBody().invoke(null);
	}
}
